package net.mcfire.aliyunplugin;

import com.alibaba.fastjson.JSONObject;
import com.google.common.hash.Hashing;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;

public class HTTP {

    public static String api_endpoint;
    public static String api_key;

    public static JSONObject api(String m, JSONObject params) throws APIException {
        if(!m.startsWith("/")) throw new IllegalArgumentException("API method must starts with /");

        JSONObject request = new JSONObject();

        String paramString = params.toJSONString();
        long time = System.currentTimeMillis()/1000L;

        String sig = Hashing.sha1().hashBytes(String.format("mcfire:%s:%d:%s", paramString, time, api_key).getBytes(StandardCharsets.UTF_8)).toString();

        request.put("d", paramString);
        request.put("t", time);
        request.put("s", sig);

        byte[] bRequest = request.toJSONString().getBytes(StandardCharsets.UTF_8);
        HTTPCallResponse response = post(api_endpoint + m, "application/json", bRequest);
        if(!response.ok) throw new APIException("api call failed");
        JSONObject ret = JSONObject.parseObject(new String(response.data, StandardCharsets.UTF_8));
        if(!ret.containsKey("status") || ret.getInteger("status") != 0) {
            throw new APIException(String.format("access denied: code<%d>(%s)", ret.getInteger("status"), ret.containsKey("message") ? ret.getString("message") : "unknown"));
        }
        return ret;
    }

    public static HTTPCallResponse post(String url, String mime, byte[] data) {
        try {
            URL u = new URL(url);
            HttpURLConnection connection = (HttpURLConnection) u.openConnection();

            connection.setRequestMethod("POST");
            connection.setRequestProperty("User-agent", "MCFireRoomServer");
            if (mime != null) connection.setRequestProperty("Content-type", mime);

            connection.setDoInput(true);
            connection.setDoOutput(data != null);

            if (data != null) {
                OutputStream os = connection.getOutputStream();
                os.write(data);
                os.close();
            }

            InputStream is = connection.getInputStream();

            return new HTTPCallResponse(connection.getResponseCode() >= 200 && connection.getResponseCode() < 400, connection.getResponseCode(), connection.getResponseMessage(), readAll(is));
        } catch (FileNotFoundException ex) {
            return new HTTPCallResponse(false, 404, "Not Found", null);
        } catch (Exception ex) {
            ex.printStackTrace();
            return new HTTPCallResponse(false, -1, "unknown", null);
        }
    }

    private static byte[] readAll(InputStream is) throws IOException {
        byte[] buffer = new byte[1024];
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        int r;
        while((r = is.read(buffer)) != -1) {
            bos.write(buffer, 0, r);
        }
        is.close();
        return bos.toByteArray();
    }

    public static class HTTPCallResponse {
        public final boolean ok;
        public final int httpCode;
        public final String httpMessage;
        public final byte[] data;

        public HTTPCallResponse(boolean ok, int httpCode, String httpMessage, byte[] data) {
            this.ok = ok;
            this.httpCode = httpCode;
            this.httpMessage = httpMessage;
            this.data = data;
        }
    }

    public static class APIException extends IOException {
        public APIException(String message) {
            super(message);
        }

        public APIException(String message, Throwable cause) {
            super(message, cause);
        }
    }


}
